/*
===========================================================================
This source file is part of DyLab (Dynamic Laboratory)
For the latest info, see http://dylab.googlecode.com

Copyright (c) 2006-2008 Lukas Krejci
(krejci.lukas@volny.cz)

This file is part of DyLab.

    DyLab is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    DyLab is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with DyLab.  If not, see <http://www.gnu.org/licenses/>.
===========================================================================
*/

#ifndef __dylab_LinearObjContainerBase_h__
#define __dylab_LinearObjContainerBase_h__

//===========================================================================================
#include <dylab/utils/containers/ContainerBase.h>
#include <dylab/utils/containers/ObjManagerBase.h>
#include <dylab/utils/types/dynamicCast.h>

//===========================================================================================
namespace dylab {

    /** 
     */   
    template <
        class _STLcontainerT
    >
    class LinearObjContainerBase 
        : public ContainerBase<_STLcontainerT>
        , public ObjManagerBase
    { 
    public:
        typedef LinearObjContainerBase<_STLcontainerT> LinearObjContainerBaseT;
        typedef typename _STLcontainerT::value_type ObjectPtrT;
    public:
        /// utility class (RIAA) for walking through all container elements
        class Iterator
            : public IteratorBase
        {
        public:
            Iterator(ContainerBaseT & _c)
                : IteratorBase(_c)
                    { }
            operator ObjectPtrT ()
                    { 
                        DYLAB_ASSERT(isValid());
                        return *getCurrent(); 
                    }
            ObjectPtrT operator()()
                    { 
                        DYLAB_ASSERT(isValid());
                        return *getCurrent(); 
                    }
            ObjectPtrT operator-> ()
                    { 
                        DYLAB_ASSERT(isValid());
                        return *getCurrent(); 
                    }
        };
        //-----------------------------------------------------------------------------
    public:
        /// utility class (RIAA) for walking through all container elements without the permission to modify them
        class ConstIterator
            : public ConstIteratorBase
        {
        public:
            ConstIterator(const ContainerBaseT & _c)
                : ConstIteratorBase(_c)
                    { }
            operator const ObjectPtrT ()
                    { 
                        DYLAB_ASSERT(isValid());
                        return *getCurrent(); 
                    }
            const ObjectPtrT operator()()
                    { 
                        DYLAB_ASSERT(isValid());
                        return *getCurrent(); 
                    }
            const ObjectPtrT operator-> ()
                    { 
                        DYLAB_ASSERT(isValid());
                        return *getCurrent(); 
                    }
        };
        //-----------------------------------------------------------------------------
    public:
        /// scoped reader class
        class Reader
            : public ReaderBase
        {
        public:
            Reader(const ContainerBaseT & _c)
                : ReaderBase(_c)
                    { }
        };
        //-----------------------------------------------------------------------------

    public:
        /// scoped writer class
        class Writer
            : public WriterBase
        {
        public:
            Writer(ContainerBaseT & _c)
                : WriterBase(_c)
                    { }
            Writer(Iterator & _activeIter)
                : WriterBase(_activeIter)
                    { }

            void insertAtFront(ObjectPtrT _value)
                    { mSTLcontainer->push_front(_value); }
            void insertAtEnd(ObjectPtrT _value)
                    { mSTLcontainer->push_back(_value); }

            ObjectPtrT removeFront()
					{
                        if (dynamicCast<LinearObjContainerBaseT>(mContainerBase)->isObjectOwner())
						{
                            delete mSTLcontainer->front();
							mSTLcontainer->pop_front();
							return NULL;
						}
						else
						{
							ObjectPtrT removedObj = mSTLcontainer->front();
							mSTLcontainer->pop_front(); 
							return removedObj;
						}
					}
            ObjectPtrT removeEnd()
                    { 
                        if (dynamicCast<LinearObjContainerBaseT>(mContainerBase)->isObjectOwner())
						{
                            delete mSTLcontainer->back();
							mSTLcontainer->pop_back();
							return NULL;
						}
						else
						{
							ObjectPtrT removedObj = mSTLcontainer->back();
							mSTLcontainer->pop_back(); 
							return removedObj;
						}
					}

            void remove(ObjectPtrT _object)
                    {                         
                        DYLAB_ASSERT(_object != NULL);
                        mSTLcontainer->remove(_object);                         
                        if (dynamicCast<LinearObjContainerBaseT>(mContainerBase)->isObjectOwner())
                            delete _object;
                    }
            void removeAll()
                    { 
                        if (dynamicCast<LinearObjContainerBaseT>(mContainerBase)->isObjectOwner())
                            for (_STLcontainerT::iterator it = mSTLcontainer->begin(); it != mSTLcontainer->end(); it++)
                                delete *it;
                        mSTLcontainer->clear();
                    }
        };
        //-----------------------------------------------------------------------------

    public:

        LinearObjContainerBase(bool _objectOwner)
            : ObjManagerBase(_objectOwner)
                { }

        virtual ~LinearObjContainerBase()
                { removeAll(); }       

        void insertAtFront(ObjectPtrT _value)
                { Writer(*this).insertAtFront(_value); }
        void insertAtEnd(ObjectPtrT _value)
                { Writer(*this).insertAtEnd(_value); }

        ObjectPtrT removeFront()
                { return Writer(*this).removeFront(); }
        ObjectPtrT removeEnd()
                { return Writer(*this).removeEnd(); }

        void remove(ObjectPtrT _object)
                { Writer(*this).remove(_object); }
        void removeAll()
                { Writer(*this).removeAll(); }

        /**
         * Returns the first object pointer in the linear container.
         */
        ObjectPtrT getFirst()
                { return Iterator(*this)(); }

        /**
         * Returns the first object pointer in the linear container.
         */
        const ObjectPtrT getFirst() const
                { return ConstIterator(*this)(); }
    };    
}
//===========================================================================================
#endif // __dylab_LinearObjContainerBase_h__
